Системное программирование

Тема 2. Процессы и задания в прикладном программном интерфейсе

Системное программирование

План лекции

1. Прикладной системный интерфейс управления системными ресурсами

2. Понятие процесса и управление процессами

3. Концепция виртуализации и контейнеризация

4. Управление группами процессов

5. Понятие многопоточности, модели потоков

6. Методы управления потоками

7. Организация параллельной обработки данных

8. Асинхронное выполнение системных вызовов

9. Удаленный запуск приложений

Процессы и задания в прикладном программном интерфейсе
Системное программирование

1. Прикладной системный интерфейс управления ресурсами

1.1. Управление системными ресурсами

Ресурсы операционной системы:

  • Процессорное время — распределение между процессами
  • Оперативная память — выделение и освобождение
  • Устройства ввода/вывода — доступ к периферии
  • Файловая система — хранение данных
  • Сетевые ресурсы — коммуникации

Функции API управления ресурсами:

  • Создание и завершение процессов
  • Управление памятью (выделение/освобождение)
  • Работа с файлами и устройствами
  • Синхронизация и координация
Процессы и задания в прикладном программном интерфейсе
Системное программирование

2. Понятие процесса и управление процессами

2.1. Что такое процесс?

Процесс — экземпляр выполняющейся программы, включающий:

  • Исполняемый код программы
  • Текущее значение программного счетчика
  • Содержимое регистров процессора
  • Стек вызовов функций
  • Данные (глобальные переменные)
  • Дескрипторы открытых файлов
  • Адресное пространство памяти

Атрибуты процесса:

  • PID (Process ID) — идентификатор процесса
  • PPID (Parent PID) — идентификатор родительского процесса
  • Приоритет и политика планирования
  • Состояние процесса
Процессы и задания в прикладном программном интерфейсе
Системное программирование

2.2. Состояния процесса

Процессы и задания в прикладном программном интерфейсе
Системное программирование

2.3. Создание процессов

В Windows (WinAPI):

#include <windows.h>

STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;

CreateProcess(
    "program.exe",    // Имя исполняемого файла
    NULL,             // Командная строка
    NULL,             // Атрибуты безопасности процесса
    NULL,             // Атрибуты безопасности потока
    FALSE,            // Наследование дескрипторов
    0,                // Флаги создания
    NULL,             // Окружение
    NULL,             // Текущий каталог
    &si,              // STARTUPINFO
    &pi               // PROCESS_INFORMATION
);
Процессы и задания в прикладном программном интерфейсе
Системное программирование

2.4. Создание процессов в Linux

Системный вызов fork():

#include <unistd.h>
#include <sys/wait.h>

pid_t pid = fork();

if (pid < 0) {
    // Ошибка создания процесса
} else if (pid == 0) {
    // Код дочернего процесса
    execl("/bin/ls", "ls", "-l", NULL);
} else {
    // Код родительского процесса
    wait(NULL);  // Ожидание завершения дочернего
}

Особенности fork():

  • Создает точную копию процесса
  • Возвращает 0 в дочернем процессе
  • Возвращает PID дочернего в родительском
  • Использует copy-on-write для оптимизации
Процессы и задания в прикладном программном интерфейсе
Системное программирование

3. Концепция виртуализации

3.1. Виртуализация ресурсов

Виртуализация — технология, позволяющая представить физические ресурсы в виде логических, абстрагированных от аппаратной реализации.

Виды виртуализации:

Тип Описание Примеры
Виртуальная память Изоляция адресных пространств Страничная организация
Виртуальные машины Полная эмуляция системы VMware, VirtualBox
Контейнеры Изоляция процессов Docker, LXC
Виртуальные устройства Абстракция оборудования /dev/null, виртуальные диски
Процессы и задания в прикладном программном интерфейсе
Системное программирование

3.2. Виртуальное адресное пространство

Секции
Стек (Stack) — ↓ растёт вниз
...
Куча (Heap) — ↑ растёт вверх
Неинициализированные данные (BSS)
Инициализированные данные (DATA)
Код программы (TEXT)
Зарезервировано ядром

Высокие адреса — сверху (Стек), Низкие адреса — снизу (Зарезервировано ядром)

Процессы и задания в прикладном программном интерфейсе
Системное программирование

3.3. Контейнеризация в Linux

Namespaces (пространства имён)

Namespaces — механизм изоляции ресурсов процесса.

Namespace Изолирует Флаг clone()
PID Идентификаторы процессов CLONE_NEWPID
NET Сетевой стек CLONE_NEWNET
MNT Точки монтирования CLONE_NEWNS
UTS Имя хоста CLONE_NEWUTS
IPC Объекты IPC CLONE_NEWIPC
USER UID/GID CLONE_NEWUSER
CGROUP Иерархия cgroups CLONE_NEWCGROUP
Процессы и задания в прикладном программном интерфейсе
Системное программирование

Пример создания namespace:

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <unistd.h>

static int child_func(void* arg) {
    printf("Child PID: %d\n", getpid());
    return 0;
}

int main() {
    char stack[1024*1024];
    
    pid_t pid = clone(child_func, stack + sizeof(stack),
                       CLONE_NEWPID | SIGCHLD, NULL);
    
    printf("Parent PID: %d, Child: %d\n", getpid(), pid);
    waitpid(pid, NULL, 0);
    return 0;
}
Процессы и задания в прикладном программном интерфейсе
Системное программирование

Cgroups (контрольные группы)

Cgroups — механизм ограничения и учёта ресурсов.

Подсистемы (контроллеры):

Контроллер Назначение
cpu Ограничение CPU
memory Ограничение памяти
blkio Ограничение I/O
devices Доступ к устройствам
freezer Приостановка процессов
Процессы и задания в прикладном программном интерфейсе
Системное программирование

Пример ограничения памяти (cgroups v2):

# Создание группы
sudo mkdir /sys/fs/cgroup/mygroup

# Установка лимита памяти (100 MB)
echo 100M > /sys/fs/cgroup/mygroup/memory.max

# Добавление процесса
echo $$ > /sys/fs/cgroup/mygroup/cgroup.procs
Процессы и задания в прикладном программном интерфейсе
Системное программирование

Контейнеры vs Виртуальные машины

center

Процессы и задания в прикладном программном интерфейсе
Системное программирование

Сравнение:

Характеристика VM Контейнер
Изоляция Полная На уровне ОС
Размер ГБ МБ
Запуск Минуты Секунды
Производительность Накладные расходы Близка к нативной
Переносимость Ограниченная Высокая
Процессы и задания в прикладном программном интерфейсе
Системное программирование

3.4. Подходы к контейнеризации: Docker, Podman, containerd, LXC

Docker — наиболее распространённая платформа контейнеризации с клиент-серверной архитектурой (демон dockerd).

Podman — альтернативный движок контейнеризации от Red Hat:

  • Не требует демона (daemonless)
  • Поддержка rootless-контейнеров (запуск без прав root)
  • Концепция pod — группа контейнеров, аналогичная Kubernetes Pod
  • CLI совместимость с Docker
podman run -d --name web nginx:latest
podman build -t myapp .
podman pod create --name mypod
podman run -d --pod mypod redis:latest
Процессы и задания в прикладном программном интерфейсе
Системное программирование

containerd — runtime-компонент контейнеризации:

  • Используется Docker и Kubernetes как низкоуровневый runtime
  • Реализует CRI (Container Runtime Interface)
  • Работает на более низком уровне, чем Docker
  • Отвечает за: pull образов, создание контейнеров, управление жизненным циклом

Процессы и задания в прикладном программном интерфейсе
Системное программирование

Сравнение инструментов контейнеризации:

Характеристика Docker Podman containerd LXC
Архитектура Клиент-сервер (демон) Daemonless Встроенный runtime Демон (lxd)
Rootless-режим Частично Полностью Частично Частично
CLI Docker-совместимость Да Нет Нет
Kubernetes CRI Через shim Через CRI-O Нативно Нет
Уровень абстракции Высокий Высокий Низкий Низкий
Целевое применение Разработка, CI/CD Разработка, K8s Продакшен runtime Системные контейнеры
Процессы и задания в прикладном программном интерфейсе
Системное программирование

3.5. Безопасность и песочница (sandboxing) процессов

Почему изоляция процессов важна для безопасности:

  • Уязвимость в одном процессе не должна compromise всю систему
  • Контейнеры и сервисы должны иметь минимально необходимые привилегии
  • Поверхность атаки (attack surface) зависит от доступных системных вызовов и ресурсов
Процессы и задания в прикладном программном интерфейсе
Системное программирование

chroot — базовая изоляция файловой системы

chroot — изменение корневого каталога для процесса и его потомков.

#include <unistd.h>

chroot("/path/to/new/root");
chdir("/");
sudo chroot /path/to/new/root /bin/bash

Ограничения chroot:

  • Не изолирует PID, сеть, IPC
  • Root-пользователь может выйти (chroot escape)
  • Только файловая изоляция — не полноценная песочница
Процессы и задания в прикладном программном интерфейсе
Системное программирование

Namespaces с точки зрения безопасности

Linux namespaces — не только изоляция для контейнеров, но и механизм безопасности:

Namespace Защита от
PID Скрытие процессов хоста
NET Изоляция сетевого стека, предотвращение MITM
MNT Сокрытие файловой системы хоста
USER Отображение UID/GID, непривилегированные контейнеры

Пример USER namespace (rootless-контейнер):

unshare --user --map-root-user bash
id
Процессы и задания в прикладном программном интерфейсе
Системное программирование

seccomp — фильтрация системных вызовов

seccomp (Secure Computing Mode) — ограничение системных вызовов процесса.

seccomp-bpf — фильтрация на основе правил BPF (Berkeley Packet Filter).

#include <seccomp.h>
#include <sys/prctl.h>

prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);

scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ERRNO(1));

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);

seccomp_load(ctx);
seccomp_release(ctx);
Процессы и задания в прикладном программном интерфейсе
Системное программирование

AppArmor и SELinux — Mandatory Access Control

AppArmor (Ubuntu, SUSE):

  • Управление доступом на основе путей к файлам
  • Профили определяют разрешённые операции
  • Режимы: enforce (блокировка) и complain (только логирование)

SELinux (RHEL, Fedora):

  • Управление доступом на основе меток (labels)
  • Более гранулярный контроль, чем AppArmor
  • Стратегии: targeted, strict, MLS
aa-status
getenforce
Характеристика AppArmor SELinux
Модель Path-based Label-based
Сложность Проще Сложнее
Гибкость Ниже Выше
Использование Ubuntu, SUSE RHEL, Fedora
Процессы и задания в прикладном программном интерфейсе
Системное программирование

Windows Job Objects — ресурсы и безопасность

Job Objects в Windows позволяют:

  • Ограничение CPU-времени для группы процессов
  • Ограничение рабочего множества памяти (working set)
  • Ограничение приоритета процессов
  • Завершение всех процессов в Job при закрытии
HANDLE hJob = CreateJobObject(NULL, L"MyJob");

JOBOBJECT_BASIC_LIMIT_INFORMATION jbli = {0};
jbli.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_TIME;
jbli.PerProcessUserTimeLimit.QuadPart = 10000000;

SetInformationJobObject(hJob, JobObjectBasicLimitInformation,
                        &jbli, sizeof(jbli));

AssignProcessToJobObject(hJob, hProcess);
Процессы и задания в прикладном программном интерфейсе
Системное программирование

Техники песочницы (sandboxing)(1/2)

Комплексный подход к изоляции:

  • Сброс capabilities — ограничение привилегий (Linux capabilities)
  • Только для чтения файловая система — предотвращение модификации
  • Сетевые ограничения — изоляция или запрет сети
  • Лимиты ресурсов — cgroups / Job Objects
  • Монтирование tmpfs — временное хранение данных
capsh --drop=cap_net_raw --drop=cap_sys_admin -- \
    --chroot=/sandbox -- /bin/bash
Процессы и задания в прикладном программном интерфейсе
Системное программирование

Техники песочницы (sandboxing)(2/2)

Процессы и задания в прикладном программном интерфейсе
Системное программирование

4. Управление группами процессов

4.1. Иерархия процессов

Группы процессов в UNIX/Linux:

  • Сессия (Session) — коллекция групп процессов
  • Группа процессов — связанные процессы (pipeline)
  • Лидер группы — процесс, создавший группу
  • Лидер сессии — процесс, создавший сессию

Управление группами:

// Создание новой группы процессов
setpgid(pid, pgid);

// Создание новой сессии
setsid();

// Отправка сигнала группе
kill(-pgid, SIGTERM);
Процессы и задания в прикладном программном интерфейсе
Системное программирование

4.2. Сигналы процессам

Основные сигналы UNIX:

Сигнал Значение Действие
SIGINT 2 Прерывание (Ctrl+C)
SIGTERM 15 Завершение
SIGKILL 9 Безусловное завершение
SIGSTOP 19 Остановка
SIGCONT 18 Продолжение
SIGCHLD 20 Завершение дочернего
Процессы и задания в прикладном программном интерфейсе
Системное программирование

5. Понятие многопоточности

5.1. Потоки выполнения

Поток (Thread) — единица выполнения внутри процесса, имеющая:

  • Собственный программный счетчик
  • Набор регистров
  • Стек вызовов
  • Состояние выполнения

Потоки разделяют в процессе:

  • Код программы
  • Глобальные данные
  • Открытые файлы
  • Сигналы
Процессы и задания в прикладном программном интерфейсе
Системное программирование

5.2. Модели потоков

Модели реализации потоков:

Модель 1:1 (One-to-One)

Windows, Linux (NPTL)

Процессы и задания в прикладном программном интерфейсе
Системное программирование

Модель Many-to-One

Green threads (устаревшие)

Процессы и задания в прикладном программном интерфейсе
Системное программирование

Модель Many-to-Many

Goroutines (Go), компромисс

Процессы и задания в прикладном программном интерфейсе
Системное программирование

6. Методы управления потоками

6.1. Создание потоков в Windows

#include <windows.h>

DWORD WINAPI ThreadFunc(LPVOID lpParam) {
    // Код потока
    return 0;
}

HANDLE hThread = CreateThread(
    NULL,              // Атрибуты безопасности
    0,                 // Размер стека
    ThreadFunc,        // Функция потока
    &param,            // Параметр
    0,                 // Флаги создания
    &threadId          // ID потока
);

WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
Процессы и задания в прикладном программном интерфейсе
Системное программирование

6.2. Создание потоков в POSIX

#include <pthread.h>

void* thread_func(void* arg) {
    // Код потока
    pthread_exit(NULL);
}

pthread_t thread;
int result = pthread_create(
    &thread,      // Идентификатор потока
    NULL,         // Атрибуты
    thread_func,  // Функция
    &param        // Аргумент
);

pthread_join(thread, NULL);
Процессы и задания в прикладном программном интерфейсе
Системное программирование

7. Организация параллельной обработки

7.1. Параллелизм и конкурентность

Конкурентность — способность системы обрабатывать несколько задач, чередуя их выполнение.

Параллелизм — одновременное выполнение нескольких задач.

Уровни параллелизма:

  • Межпроцессный — независимые процессы
  • Межпоточный — потоки одного процесса
  • Внутрипоточный — инструкции (конвейеризация)

Преимущества:

  • Повышение производительности
  • Лучшее использование ресурсов
  • Отзывчивость приложений
Процессы и задания в прикладном программном интерфейсе
Системное программирование

7.2. Проблемы параллельной обработки

Основные проблемы:

  • Состояние гонки (Race Condition)
  • Взаимная блокировка (Deadlock)
  • Голодание (Starvation)
  • Проблема ABA

Пример состояния гонки:

// Общая переменная
int counter = 0;

// Поток 1          // Поток 2
int temp = counter;  int temp = counter;
temp++;              temp++;
counter = temp;      counter = temp;
// Результат: counter = 1 (вместо 2!)
Процессы и задания в прикладном программном интерфейсе
Системное программирование

8. Асинхронное выполнение системных вызовов

8.1. Синхронный vs Асинхронный ввод-вывод

Синхронный (блокирующий):

// Поток блокируется до завершения операции
ReadFile(hFile, buffer, size, &read, NULL);
// Выполнение продолжается только после чтения

Асинхронный (неблокирующий):

OVERLAPPED ov = {0};
ReadFileEx(hFile, buffer, size, &ov, CompletionCallback);
// Поток продолжает выполнение
// Callback вызывается по завершении
Процессы и задания в прикладном программном интерфейсе
Системное программирование

8.2. Механизмы асинхронности

Windows:

  • Overlapped I/O
  • I/O Completion Ports (IOCP)
  • Asynchronous Procedure Calls (APC)

Linux:

  • aio (asynchronous I/O)
  • epoll
  • io_uring (современный)

Пример epoll:

int epfd = epoll_create1(0);
struct epoll_event ev, events[10];
ev.events = EPOLLIN;
ev.data.fd = sockfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
int nfds = epoll_wait(epfd, events, 10, -1);
Процессы и задания в прикладном программном интерфейсе
Системное программирование

9. Удаленный запуск приложений

9.1. Механизмы удаленного выполнения

Способы удаленного запуска:

  • SSH — безопасное удаленное выполнение (Linux)
  • RPC — удаленный вызов процедур
  • DCOM/COM+ — распределенные объекты (Windows)
  • WMI — Windows Management Instrumentation

Пример SSH:

# Выполнение команды на удаленном хосте
ssh user@remote_host "ls -la"

# Копирование файлов
scp file.txt user@remote_host:/path/
Процессы и задания в прикладном программном интерфейсе
Системное программирование

9.2. RPC (Remote Procedure Call)

Концепция RPC:

Процессы и задания в прикладном программном интерфейсе
Системное программирование

Резюме

Ключевые моменты лекции:

  1. Процесс — изолированная единица выполнения с собственными ресурсами
  2. Виртуализация — абстракция физических ресурсов
  3. Namespaces и cgroups — механизмы изоляции для контейнеров
  4. Docker, Podman, containerd, LXC — экосистема контейнеризации
  5. Потоки — легковесные единицы выполнения внутри процесса
  6. Параллельная обработка — требует синхронизации
  7. Асинхронный I/O — повышает производительность
  8. Удаленный запуск — распределенные вычисления
  9. seccomp, AppArmor/SELinux — механизмы безопасности и песочница процессов
Процессы и задания в прикладном программном интерфейсе
Системное программирование

Вопросы для самопроверки

  1. Чем отличается процесс от потока?
  2. Какие состояния может иметь процесс?
  3. Что такое виртуальное адресное пространство?
  4. Какие namespaces существуют в Linux?
  5. Как работают cgroups?
  6. Какие модели потоков существуют?
  7. Что такое состояние гонки и как его избежать?
  8. Какие механизмы асинхронного ввода-вывода существуют?
  9. Как работает механизм RPC?
Процессы и задания в прикладном программном интерфейсе
Системное программирование

Практические задания

Самостоятельная работа (8 часов):

  1. Написать программу, создающую дочерний процесс (fork/clone)
  2. Исследовать /proc/[pid]/ для анализа процессов
  3. Создать простую программу с использованием pthread
  4. Изучить работу namespaces на примере unshare
Процессы и задания в прикладном программном интерфейсе
Системное программирование

Рекомендуемая литература

Основная:

  1. Таненбаум, Э. Современные операционные системы. — 4-е изд. — СПб.: Питер, 2021.
  2. Kerrisk, M. The Linux Programming Interface. — No Starch Press, 2010.
  3. Бутенхоф, Д. Программирование с использованием POSIX Threads. — СПб.: Символ-Плюс, 2002.

Дополнительная:

  1. namespaces(7), cgroups(7), fork(2), clone(2), pthread_create(3), seccomp(2), capabilities(7)
  2. Docker Documentation: https://docs.docker.com/
  3. Linux Kernel Documentation: https://www.kernel.org/doc/
  4. Man7.org — справочник системных вызовов: https://man7.org/linux/man-pages/
  5. Podman Documentation: https://docs.podman.io/
  6. containerd Documentation: https://containerd.io/
Процессы и задания в прикладном программном интерфейсе

Кратко пробежаться по плану, подчеркнуть, что сегодня центральная тема — процессы и потоки, а виртуализация и контейнеризация будут рассмотрены как практическое применение этих концепций. На всю лекцию заложено ~90 минут.

Этот слайд — введение. Спросить студентов: «Какие ресурсы ОС вы уже использовали в программировании?» Упомянуть, что дальше мы подробно разберём каждый пункт. На слайде 2-3 минуты.

Ключевое различие: программа — это файл на диске, процесс — это выполняющийся экземпляр. Показать `ps aux` в терминале для наглядности. Спросить: «Чем отличается процесс от потока?» — ответ дадим позже.

Нарисовать переходы на доске и проговорить каждый. Типичный вопрос: «Что заставляет процесс перейти из Выполнения в Ожидание?» — системный вызов I/O, ожидание ресурса. Обратить внимание, что из Ожидания процесс переходит в Готов, а не напрямую в Выполнение.

Подчеркнуть, что Windows-подход — явное создание нового процесса с загрузкой исполняемого файла. Обратить внимание на структуры STARTUPINFO и PROCESS_INFORMATION — они содержат много параметров, которые по умолчанию можно оставить NULL. Не застревать на каждом параметре, главное — общая картина.

Ключевой слайд. Обязательно разобрать fork() по строкам. Распространённая ошибка студентов — забывать, что после fork() код выполняется в двух процессах. Спросить: «Что выведет printf, если поставить его до if?» Показать copy-on-write на примере: пока процессы не модифицируют память, страницы не разделяются.

Виртуальная память уже знакома студентам из архитектуры ЭВМ — связать с этим. Основной акцент на том, что виртуализация решает проблему изоляции и эффективного использования ресурсов. Переход к следующему слайду: покажем, как виртуальная память выглядит внутри процесса.

Спросить: «Почему стек растёт вниз, а куча вверх?» — чтобы максимально использовать адресное пространство. Упомянуть утилиту `size` в Linux, которая показывает размеры секций. Обратить внимание на зарезервированную область — доступна только ядру, при обращении из userspace будет segmentation fault.

Это большой слайд — на него 10-12 минут. Namespaces изолируют «видимость» ресурсов, cgroups — ограничивают «потребление». Показать `unshare -p -f --mount-proc bash` в терминале — наглядная демонстрация. По сравнению VM vs контейнеры: контейнеры НЕ обеспечивают полную изоляцию (общее ядро!), это важно подчеркнуть для безопасности.

Подчеркнуть: Podman — drop-in замена Docker для большинства команд. Rootless-режим повышает безопасность: уязвимость в контейнере не даёт прав root на хосте. Pod — удобная абстракция для миграции в Kubernetes.

containerd — «движок под капотом». Docker с версии 1.11 использует containerd. Kubernetes может работать напрямую с containerd, минуя Docker (так называемый cri-containerd). Упомянуть, что runC — это OCI-совместимый runtime.

LXC — «классическая» контейнеризация Linux, ближе к лёгким ВМ. Docker и Podman — ориентированы на приложения. containerd — для интеграции в оркестраторы. Спросить: «Какой инструмент выбрать для локальной разработки?» — Docker или Podman.

Связать с предыдущим разделом: контейнеры используют namespaces + cgroups, но это НЕ полная изоляция. Далее рассмотрим дополнительные механизмы безопасности.

chroot — исторически первый механизм изоляции (с 1979 года). Показать, что chroot недостаточен для безопасности: продемонстрировать, что `ls /proc` внутри chroot видит процессы хоста.

USER namespace — ключевой для rootless-контейнеров в Podman. Процесс считает себя root внутри namespace, но на хосте — обычный пользователь. Спросить: «Какой namespace наиболее важен для безопасности?» — все вместе, но USER критичен для rootless.

seccomp — один из самых мощных механизмов. Docker по умолчанию запрещает ~44 системных вызова. Спросить: «Что произойдёт, если процесс вызовет запрещённый syscall?» — получит errno. Практическое задание: посмотреть seccomp-профиль Docker через `docker info`.

В контексте контейнеров: Docker поддерживает оба механизма. Podman — преимущественно SELinux (Red Hat). Спросить: «Какой механизм используется на ваших рабочих станциях?» — зависит от дистрибутива.

Job Objects — уникальный механизм Windows, не имеющий прямого аналога в Linux (cgroups частично компенсируют). В контексте безопасности: Job Object может запретить созданным внутри него процессам определённые действия (например, создание окон, доступ к буферу обмена).

Пояснить: ни один механизм не даёт полной защиты. Только комбинация нескольких подходов обеспечивает надёжную изоляцию. Именно так работают контейнеры: namespaces + cgroups + seccomp + MAC. Ссылки: man7.org — namespaces(7), capabilities(7), seccomp(2).

Показать на примере `ps -eo pid,ppid,pgid,sid,cmd`. Спросить: «Что произойдёт, если завершить лидер группы процессов?» — группа продолжает работать, но теряет лидера. Упомянуть `nohup` и `disown` как практические инструменты, которые студенты уже могли использовать.

Ключевой момент: SIGKILL и SIGSTOP невозможно перехватить или обработать — это важно для понимания управления процессами. Спросить: «Чем отличается SIGTERM от SIGKILL?» — SIGTERM позволяет процессу корректно завершиться (освободить ресурсы), SIGKILL — мгновенное убийство. Показать `kill -l` для полного списка.

Вернуться к вопросу «Чем отличается процесс от потока?» из начала лекции. Нарисовать на доске: один процесс = одна таблица страниц, много потоков = одно адресное пространство, разные стеки. Ключевая выгода: переключение между потоками дешевле, чем между процессами (не нужно переключать адресное пространство).

Акцентировать модель 1:1 — она стандартна в современных ОС. Many-to-One устарела, потому что блокировка одного потока блокирует все. Many-to-Many сложна в реализации. Упомянуть goroutines в Go как пример M:N, реализованный на уровне runtime (не ядра).

Показать параллель с CreateProcess — API Windows следует единому стилю. Обратить внимание на CloseHandle — дескриптор потока нужно закрывать, иначе утечка ресурсов. WaitForSingleObject — аналог join в POSIX.

Сравнить с Windows-версией: pthread_create проще, но меньше контроля. Важно: при компиляции нужно `-lpthread`. Спросить: «Что будет, если не вызвать pthread_join?» — процесс завершится, даже если поток ещё работает (в отличие от wait для процессов).

Обязательно разграничить конкурентность и параллелизм — это частый вопрос на экзамене. Конкурентность — про структуру программы, параллелизм — про исполнение. Показать пример: одноядерный процессор с конкурентными задачами (псевдопараллелизм) vs многоядерный с истинным параллелизмом.

Разобрать пример по шагам на доске, показав interleaving. Спросить: «Как исправить?» —.mutex/критическая секция. Кратко упомянуть deadlock: условия Коэна (взаимное исключение, удержание, отсутствие предобработки, циклическое ожидание). Проблема ABA — связь со следующей темой (атомарные операции).

Начать с вопроса: «Что произойдёт, если поток заблокируется на I/O?» — простой ответ: он не может делать ничего другого. В одно поточной программе это означает зависание интерфейса. Показать связь с отзывчивостью GUI-приложений.

IOCP в Windows — золотой стандарт для высоконагруженных серверов. В Linux эволюция: select → poll → epoll → io_uring. io_uring — самый современный механизм, основан на кольцевых буферах, минимизирует системные вызовы. Упомянуть, что epoll используется в Nginx, Redis и других высокопроизводительных системах.

SSH студенты уже знают из практики — связать с этим. Основной акцент на RPC и WMI как программных механизмах. Спросить: «Какие ещё способы удалённого запуска вы знаете?» — возможные ответы: RDP, Ansible, systemd-nspawn.

Подчеркнуть: RPC создаёт иллюзию локального вызова, но под капотом — сериализация, сетевая передача и десериализация. Спросить: «В чём недостатки RPC по сравнению с локальным вызовом?» — задержка сети, отсутствие общих ссылок, проблемы с типами данных. Упомянуть gRPC и protobuf как современную реализацию.

Пробежаться по пунктам, спросить студентов, какой раздел показался наиболее сложным. Упомянуть, что на следующей лекции углубимся в синхронизацию и примитивы взаимодействия процессов.

Рекомендовать студентам ответить на вопросы дома перед практическим занятием. Вопросы 7 и 8 — наиболее сложные, по ним будет больше задач на практике.

Задания 1 и 3 — обязательные для всех. Задание 2 полезно для понимания внутренней структуры процесса через procfs. Задание 4 — для продвинутых студентов. Напомнить: для сдачи нужен отчёт с выводами и скриншотами.